﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpSvn;
using log4net;
using System.IO;

namespace PreCommitHook
{
    public class SvnRepository : ISvnRepository
    {
        private readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        
        /// <summary>
        /// retrieves the SVN revision info.
        /// </summary>
        /// <param name="transactionId">The transaction id.</param>
        /// <param name="repositoryPath">The repository path.</param>
        /// <returns>object which contains the commit operation details</returns>
        public ISVNChangeInfo GetSvnRevisionInfo(string transactionId, string repositoryPath)
        {
            using (SvnLookClient svnLookClient = new SvnLookClient())
            {
                log.Info(String.Format("GetSvnRevisionInfo with path:{0} and transactionId: {1}", repositoryPath, transactionId));
                SvnChangeInfoEventArgs info;
               
                bool result = svnLookClient.GetChangeInfo(new SvnLookOrigin( repositoryPath, transactionId) , out info);
                log.Info(String.Format("GetSvnRevisionInfo log message: '{0}'", info.LogMessage));

                if (result == false)
                {
                   log.Fatal(String.Format("Unable to retrieve information for {0}, {1}", transactionId, repositoryPath));
                   throw new ApplicationException(String.Format("Unable to retrieve information for {0}, {1}", transactionId, repositoryPath));
                }

                return new SVNChangeItemInfo(info);
            }
        }

        /// <summary>
        /// gets the assembly for the committed *.cs file
        /// </summary>
        /// <param name="fileNameToCommit">the file which is committed</param>
        /// <param name="projectFilesFolderPath">the path to the folder with *.csproj files on the svn server</param>
        /// <param name="changedItemPath">svn path</param>
        /// <returns>asembly name to which committed file belongs</returns>
        public string GetAssemblyByFile(string fileNameToCommit, string projectFilesFolderPath, string changedItemPath, ref bool isTestAssembly)
        {

            string lastAssemblyFound = String.Empty;
            string lastProjFileFound = String.Empty;

            bool assmeblyExistsInXML = false;
            foreach (string csProjFile in Directory.GetFiles(projectFilesFolderPath))
            {
                System.IO.StreamReader projectFile = new System.IO.StreamReader(csProjFile);
                string content = projectFile.ReadToEnd();
                
                projectFile.Close();
                string projFileNoExt = Path.GetFileNameWithoutExtension(csProjFile);
                string assemblyName = String.Empty;

                if (AssemblyHelper.GetAssemblyNameFromFileIfExists(fileNameToCommit, projFileNoExt, ref assemblyName))
                {
                    string assemblyNameWithNoExt = assemblyName.Substring(0, assemblyName.LastIndexOf('.'));

                    if (AssemblyHelper.AssemblyNameMatch(changedItemPath, assemblyNameWithNoExt)) 
                    {
                        log.Info(String.Format("assembly {0} found in SolutionAssemblies.xml and the path {1} contains it.", assemblyNameWithNoExt, changedItemPath));
                        lastAssemblyFound = assemblyName;
                        lastProjFileFound = projFileNoExt;
                        assmeblyExistsInXML = true;
                        break;
                    }         
                   
                }

                assemblyName = AssemblyHelper.GetExecutingAssembly(projFileNoExt, content, fileNameToCommit);
                if (assemblyName == string.Empty) continue; //no match is found

                lastAssemblyFound = assemblyName;
                lastProjFileFound = projFileNoExt;

                string assemblyNameNoExt = assemblyName.Substring(0, assemblyName.LastIndexOf('.'));

                if (AssemblyHelper.AssemblyNameMatch(changedItemPath, assemblyNameNoExt))
                {                  
                    break;
                }                
            }

            //check if the found assembly is test assembly and set the flag to true
            isTestAssembly = false;
            if (!ContentPolicyManager.ShouldCheckAssembly(lastAssemblyFound))
            {
                log.Info(String.Format("Assembly {0} is the test assembly and should not be checked for code coverage", lastAssemblyFound));
                isTestAssembly = true;
            }
            else
            {
                if (false == assmeblyExistsInXML)
                {
                    log.Info(String.Format("SolutionAssemblies.xml will be appended for proj file {0}, assembly {1}, file {2}", lastProjFileFound, lastAssemblyFound, fileNameToCommit));
                    SolutionAssembliesWriter.Write(lastProjFileFound, lastAssemblyFound, fileNameToCommit);
                }
            }

            log.Info(String.Format("Assembly {0} found for file {1}", lastAssemblyFound, fileNameToCommit));
            return lastAssemblyFound;
        }

    }
}
